package me.flyray.bsin.blockchain.conflux;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Keys;
import org.web3j.crypto.Wallet;
import org.web3j.crypto.WalletFile;
import org.web3j.crypto.WalletUtils;
import org.web3j.protocol.ObjectMapperFactory;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import conflux.web3j.Account;
import conflux.web3j.CfxUnit;
import conflux.web3j.Web3;
import conflux.web3j.types.Address;
import lombok.extern.slf4j.Slf4j;
import me.flyray.bsin.blockchain.BsinBlockChainEngine;
import me.flyray.bsin.blockchain.dto.ChainWalletDto;
import me.flyray.bsin.blockchain.utils.BsinDefaultFunctionEncoder;
import me.flyray.bsin.blockchain.utils.Java2ContractTypeConcert;
import me.flyray.bsin.constants.ResponseCode;
import me.flyray.bsin.enums.ChainEnv;
import me.flyray.bsin.enums.ChainType;
import me.flyray.bsin.exception.BusinessException;

/**
 * @author bolei
 * @date 2023/6/26 15:52
 * @desc
 */

@Slf4j
@Service
public class ConfluxBiz implements BsinBlockChainEngine {

    private String ipfsGateway;

    private String privateKey;

    private String confluxRpcUrlTest;

    private String confluxRpcUrlMain;

    private String chainType;

    private Web3 web3;
    private Web3 web3Test;

    private BigInteger gasLimit;
    private BigInteger storageLimit;
    private BigInteger gasPrice;
    private BigInteger value = BigInteger.ZERO;
    private BigInteger epochHeight;
    private BigInteger chainId;

    // web3j 编码类
    private BsinDefaultFunctionEncoder bsinDefaultFunctionEncoder;

    public ConfluxBiz() {
//        this.web3Test = Web3.create(this.confluxRpcUrlTest, 3, 10000);
//        this.web3 = Web3.create(this.confluxRpcUrlMain, 3, 10000);
        this.confluxRpcUrlTest = "https://test.confluxrpc.com/v2";
        this.confluxRpcUrlMain = "https://portal-main.confluxrpc.com";
        this.privateKey = "6e88746088c5d054f983131babd915eac2764879c5b732044bfed903fe70c";
        this.ipfsGateway = "https://ipfs.s11edao.com/ipfs/";
        this.web3Test = Web3.create("https://test.confluxrpc.com/v2", 3, 10000);
        this.web3 = Web3.create("https://portal-main.confluxrpc.com", 3, 10000);
        this.bsinDefaultFunctionEncoder = new BsinDefaultFunctionEncoder();
        chainType = ChainType.CONFLUX.getCode();
    }

//    private static CofluxWeb3 cofluxSingleton;
//
//    public static CofluxWeb3 getInstance() {
//        return SingletonHander.cofluxSingleton;
//    }
//
//    private static class SingletonHander {
//        private static final CofluxWeb3 cofluxSingleton = new CofluxWeb3();
//    }

    @Override
    public Map<String, String> createWallet(String password, String chainEnv) throws Exception {
        WalletFile walletFile;
        ECKeyPair ecKeyPair = Keys.createEcKeyPair();
        walletFile = Wallet.createStandard(password, ecKeyPair);
        log.info("conflux wallet address: {}", walletFile.getAddress());
        ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(walletFile);
        log.info("keystore json file: {}", jsonStr);
        Credentials credentials = WalletUtils.loadJsonCredentials(password, jsonStr);
        BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey();
        String sPrivatekeyInHex = privateKey.toString(16);
        Map map = createAccount(chainEnv, sPrivatekeyInHex, null, null, null);
        Account account = (Account) map.get("account");
        // 返回参数
        Map<String, String> result = new HashMap<>();
        result.put("keystoreJson", jsonStr);
        result.put("address", account.getAddress().toString());
        result.put("privateKey", sPrivatekeyInHex);
        return result;
    }

    @Override
    public Map<String, Object> createAccount(String chainEnv, String privateKey, String gasPrice, String gasLimit, String value) {
        Map map = new HashMap();
        Account.Option opt = new Account.Option();
        Account account;
        if (ChainEnv.MAIN.getCode().equals(chainEnv)) {
            account = Account.create(web3, privateKey);
            opt.withChainId(1029);
        } else {
            account = Account.create(web3Test, privateKey);
            opt.withChainId(1);
        }
        if (gasPrice != null) {
            opt.withGasPrice(new BigInteger(gasPrice));
        }
        // gasLimit和storageLimit为空时使用estimateGasAndCollateral 自动预估
        if (gasLimit != null) {
            opt.withGasLimit(new BigInteger(gasLimit));
        }
        if (value != null) {
            opt.withValue(new BigInteger(value));
        }
        map.put("opt", opt);
        map.put("account", account);
        return map;
    }

    @Override
    public String getAddress(String chainEnv, String privateKey) {
        return null;
    }

    @Override
    public String getPrivateKey() {
        return null;
    }

    @Override
    public String getBalance(String chainEnv, String address) throws Exception {
        return null;
    }

    @Override
    public String getIpfsGateway() {
        return null;
    }

    @Override
    public String getZeroAddress(String chainEnv) {
        return null;
    }

    @Override
    public String getWeb3ClientVersion(String chainEnv) {
        return null;
    }

    @Override
    public long getHeight(String chainEnv) {
        return 0;
    }

    @Override
    public String getTreasuryContractAddress(String chainEnv, String daoAddressStr, String wrapperOrExtensionName, boolean byFactory, boolean isInsert) {
        return null;
    }

    @Override
    public String getVaultsContractAddress(String chainEnv, String daoAddressStr, String wrapperOrExtensionName, boolean byFactory, boolean isInsert) {
        return null;
    }

    @Override
    public String getDaoWrapperOrExtensionAddressByName(String chainEnv, String daoAddressStr, String wrapperOrExtensionName, boolean isInsert) {
        return null;
    }

    @Override
    public String getDaoNameByAddress(String chainEnv, String daoAddressStr, boolean isInsert) {
        return null;
    }

    @Override
    public String getDaoAddressByIndex(String chainEnv, String daoIndex, boolean isInsert) {
        return null;
    }

    @Override
    public String getDaoAddressByName(String chainEnv, String daoName, boolean isInsert) {
        return null;
    }

    @Override
    public Map<String, Object> transfer(String chainEnv, String fromPrivateKey, String gasPrice, String gasLimit, String value, String toAddress) throws Exception {
        return null;
    }

    @Override
    public Map<String, Object> contractWrite(String chainEnv, String privateKey, String gasPrice, String gasLimit, String value, String contractAddress, String method, List<Java2ContractTypeConcert> functionReturnType, List<Java2ContractTypeConcert> functionInputParams) throws Exception {
        return null;
    }

    @Override
    public Map<String, Object> contractWrite(String chainEnv, String privateKey, String gasPrice, String gasLimit, String value, String contractAddress, String method, String methodId, List<Java2ContractTypeConcert> functionReturnType, List<Java2ContractTypeConcert> functionInputParams) throws Exception {
        return null;
    }

    @Override
    public Map<String, Object> contractDeploy(String chainEnv, String privateKey, String gasPrice, String gasLimit, String value, String byteCode, List<Java2ContractTypeConcert> functionReturnType, List<Java2ContractTypeConcert> functionInputParams) throws Exception {
        return null;
    }

    @Override
    public Map<String, Object> contractRead(String chainEnv, String contractAddress, String method, List<Java2ContractTypeConcert> functionReturnType, List<Java2ContractTypeConcert> functionInputParams) throws Exception {
        return null;
    }

    @Override
    public Map<String, Object> getSponsor(Map<String, Object> requestMap) throws Exception {
        return null;
    }

    @Override
    public Map<String, Object> setSponsor(Map<String, Object> requestMap) throws Exception {
        return null;
    }

    @Override
    public Map<String, Object> addWhiteList(Map<String, Object> requestMap) throws Exception {
        return null;
    }

    @Override
    public Map<String, Object> isWhitelisted(Map<String, Object> requestMap) throws Exception {
        return null;
    }

    @Override
    public Map<String, Object> removeWhiteList(Map<String, Object> requestMap) throws Exception {
        return null;
    }
}
